package com.koushikdutta.ion.conscrypt;

import com.example.ohosasynclibrary.async.AsyncSSLSocketWrapper;
import com.example.ohosasynclibrary.async.future.Cancellable;
import com.example.ohosasynclibrary.async.http.AsyncSSLSocketMiddleware;
import com.example.ohosasynclibrary.async.http.SimpleMiddleware;
import com.example.ohosasynclibrary.async.util.LogUtil;
import com.koushikdutta.ion.IonLog;
import ohos.app.Context;

import javax.net.ssl.SSLContext;

/**
 * Created by koush on 7/13/14.
 */
public class ConscryptMiddleware extends SimpleMiddleware {
    final static Object lock = new Object();
    static boolean initialized;
    static boolean success;
    boolean instanceInitialized;
    boolean enabled = true;

    private static final String LOGTAG = "IonConscript";

    public void enable(boolean enabled) {
        this.enabled = enabled;
        if (!enabled) {
            instanceInitialized = false;
            middleware.setSSLContext(null);
        }
    }

    public static void initialize(Context context) {
        try {
            synchronized (lock) {
                if (initialized)
                    return;

                initialized = true;


                // GMS Conscrypt is already initialized, from outside ion. Leave it alone.
//                if (Security.getProvider(ProviderInstaller.PROVIDER_NAME) != null) {
//                    success = true;
//                    return;
//                }

                SSLContext originalDefaultContext = SSLContext.getDefault();
//                SSLSocketFactory originalDefaultSSLSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory();

//                ProviderInstaller.installIfNeeded(context);
//
//                Provider[] providers = Security.getProviders();
//                Provider provider = Security.getProvider(ProviderInstaller.PROVIDER_NAME);
//                Security.removeProvider(ProviderInstaller.PROVIDER_NAME);
//                Security.insertProviderAt(provider, providers.length);
                SSLContext.setDefault(originalDefaultContext);
//                originalDefaultContext.init();
//                HttpsURLConnection.setDefaultSSLSocketFactory(originalDefaultSSLSocketFactory);
                success = true;
            }
        } catch (Throwable e) {
            IonLog.w(LOGTAG, "Conscrypt initialization failed." + e.getMessage());
        }
    }

    public void initialize() {
        initialize(context);
        if (success && !instanceInitialized && enabled) {
            instanceInitialized = true;
            try {
                final SSLContext sslContext = SSLContext.getInstance("TLS", "");
                sslContext.init(null, null, null);
                // only set the SSL context if it is the default SSL context
                if (middleware.getSSLContext() == AsyncSSLSocketWrapper.getDefaultSSLContext())
                    middleware.setSSLContext(sslContext);
            } catch (Exception e) {
                LogUtil.error(ConscryptMiddleware.class.getName(), e.getMessage());
            }
        }
    }

    AsyncSSLSocketMiddleware middleware;
    Context context;

    public ConscryptMiddleware(Context context, AsyncSSLSocketMiddleware middleware) {
        this.middleware = middleware;
        this.context = context.getApplicationContext();
    }

    @Override
    public Cancellable getSocket(GetSocketData data) {
        if (!enabled) {
            return null;
        }
        // initialize here vs the constructor, or this will potentially block the ui thread.
        initialize();
        return super.getSocket(data);
    }
}
